<template>
  <a-cascader
    :value="value"
    @change="valueChange"
    :options="options"
    :load-data="requestData"
    v-bind="$attrs"
    v-on="$listeners"
  />
</template>

<script>
function listToTree (data, id, parentId, children) {
  const config = {
    id: id || 'id',
    parentId: parentId || 'pid',
    childrenList: children || 'children'
  }

  var childrenListMap = {}
  var nodeIds = {}
  var tree = []

  for (const d of data) {
    const parentId = d[config.parentId]
    if (childrenListMap[parentId] == null) {
      childrenListMap[parentId] = []
    }
    nodeIds[d[config.id]] = d
    childrenListMap[parentId].push(d)
  }

  for (const d of data) {
    const parentId = d[config.parentId]
    if (nodeIds[parentId] == null) {
      tree.push(d)
    }
  }

  for (const t of tree) {
    adaptToChildrenList(t)
  }

  function adaptToChildrenList (o) {
    if (childrenListMap[o[config.id]] !== null) {
      o[config.childrenList] = childrenListMap[o[config.id]]
    }
    if (o[config.childrenList]) {
      for (const c of o[config.childrenList]) {
        adaptToChildrenList(c)
      }
    }
  }
  return tree
}
export default {
  name: 't-cascader',
  props: {
    value: {
      type: Array
    },
    option: {
      type: Array,
      default: () => ([])
    },
    loadData: {
      type: Function,
      require: true
    },
    id: {
      type: String,
      default: 'id'
    },
    pid: {
      type: String,
      default: 'pid'
    }

  },
  watch: {
    option: {
      handler (nv) {
        this.options = nv
      },
      deep: true
    }
  },
  data () {
    return {
      options: this.option
    }
  },
  mounted () {
    if (this.value.length) {
      this.loadOptionsAll()
    } else {
      this.getOption()
    }
  },
  methods: {
    getOption (currentOptions) {
      const first = !currentOptions
      if (!first) {
        currentOptions.loading = true
      }

      this.loadData({ ...currentOptions, first }, (list) => {
        if (first) {
          this.options = list
        } else {
          this.$set(currentOptions, 'children', [])
          currentOptions.children.push(...list)
        }
        if (!first) {
          currentOptions.loading = false
        }
      })
    },
    requestData (selectedOptions) {
      const targetOption = selectedOptions[selectedOptions.length - 1]
      this.$set(targetOption, 'children', [])
      this.getOption(targetOption)
    },
    valueChange (value) {
      this.$emit('input', value)
      this.$emit('change', value)
    },
    loadOptionsAll () {
      const len = this.value.length - 1
      let count = -1
      const list = []
      for (let i = -1; i < len; i++) {
        count++
        if (i === -1) {
          this.loadData({ first: true }, (listResult) => {
            list.push(...listResult)
            if (count === len) {
              this.options = listToTree(list, this.id, this.pid, 'children')
            }
          })
        } else {
          this.loadData({ first: false, [this.id]: this.value[i] }, (listResult) => {
            list.push(...listResult)
            if (count === len) {
              this.options = listToTree(list, this.id, this.pid, 'children')
            }
          })
        }
      }
    }
  }

}
</script>

<style scoped>

</style>
